package asteroids.model.programs.expressions.ComposedExpressions.BinaryExpressions;

import asteroids.Util;
import asteroids.model.SpaceObject;
import asteroids.model.programs.expressions.BasicExpression;
import asteroids.model.programs.expressions.Expression;
import asteroids.model.programs.expressions.BasicExpressions.BooleanLiteral;
import asteroids.model.programs.expressions.BasicExpressions.DoubleLiteral;
import asteroids.model.programs.expressions.BasicExpressions.Entity;
import asteroids.model.programs.expressions.BasicExpressions.Null;
import asteroids.model.programs.expressions.ComposedExpressions.BinaryExpression;
import asteroids.model.programs.types.Type;

public class Inequality extends BinaryExpression {
	
	/**
	 * Initialize the Inequaltiy object
	 * 
	 * @param leftExp
	 * 			The left operand of this expression
	 * @param rightExp
	 * 			The right operand of this expression
	 * @effect ...
	 * 			|super(leftExp, rigthExp)
	 */
	public Inequality(Expression leftExp, Expression rightExp, int line, int column){
		super(leftExp, rightExp, line, column);
	}

	/**
	 * Returns the symbol for this Expression, namely !=
	 * 
	 * @return ...
	 * 			| return "!="
	 */
	@Override
	public String getOperatorSymbol() {
		return "!=";
	}

	/**
	 * Returns the BasicExpression of type BooleanLiteral with the result of the expression
	 * 
	 * @return Operands are of type DoubleLiteral
	 * 			| if(getLeftOperand() instanceof DoubleLiteral && getRightOperand() instanceof DoubleLiteral)
	 * 			|	 result.equals(new BooleanLiteral(getLeftOperand().getResult().getValue()!=
	 * 												getRightOperand().getResult.getValue())
	 * 
	 * @return Operands are of type BooleanLiteral
	 * 			| if(getLeftOperand() instanceof BooleanLiteral && getRightOperand() instanceof BooleanLiteral)
	 * 			|	result.equals(new BooleanLiteral(getLeftOperand().getResult().getValue()!=
	 * 												getRightOperand().getResult.getValue())
	 * 
	 * @return Operands are of type Entity
	 * 			| if(getLeftOperand() instanceof BooleanLiteral && getRightOperand() instanceof BooleanLiteral)
	 * 			|	result.equals(new BooleanLiteral(getLeftOperand().getResult().getValue()!=
	 * 												getRightOperand().getResult.getValue())
	 */
	@Override
	public BasicExpression getResult() {
		BasicExpression result;
		
		BasicExpression leftOperand = getLeftOperand().getResult();
		BasicExpression rightOperand = getRightOperand().getResult();
		
		//Both instances of DoubleLiteral
		if(leftOperand instanceof DoubleLiteral && rightOperand instanceof DoubleLiteral){
			double leftValue = ((DoubleLiteral) leftOperand).getValue();
			double rightValue = ((DoubleLiteral)rightOperand).getValue();
			boolean resultValue = !Util.fuzzyEquals(leftValue, rightValue);
			result = new BooleanLiteral(resultValue, getLine(), getColumn());
			return result;
		}
		
		//Both instances of BooleanLiteral
		else if(leftOperand instanceof DoubleLiteral && rightOperand instanceof DoubleLiteral){
			boolean leftValue = ((BooleanLiteral)leftOperand).getValue();
			boolean rightValue = ((BooleanLiteral)rightOperand).getValue();
			boolean resultValue = leftValue != rightValue;
			result = new BooleanLiteral(resultValue, getLine(), getColumn());
			return result;
		}
		
		//Both instances of entity
		else if(leftOperand instanceof Entity && rightOperand instanceof Entity){
			SpaceObject leftValue = ((Entity)leftOperand).getValue();
			SpaceObject rightValue = ((Entity)rightOperand).getValue();
			boolean resultValue = leftValue != rightValue;
			result = new BooleanLiteral(resultValue, getLine(), getColumn());
			return result;
		}
		
		//Both instances of Null
		else if(leftOperand instanceof Null && rightOperand instanceof Null){
			result = new BooleanLiteral(true, getLine(), getColumn());
			return result;
		}
		
		else{
			result = new BooleanLiteral(true, getLine(), getColumn());
			return result;
		}
	}
	
	@Override
	public Type getType(){
		return Type.BOOLEAN;
	}
	
	@Override
	public Type[] getOperandType(){
		return new Type[]{Type.ANY};
	}

}
